"""
Administrative endpoints for CodeMCP API.

Provides administrative functions including configuration management,
system control, and monitoring operations.
"""

from typing import Dict, Any, List, Optional
from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks, Query, Security
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import asyncio
from datetime import datetime
import uuid

from ...core.error_handler import handle_error, log_info, log_warning
from ...core.config import Config
from ...core.tool_registry import get_tool_registry, ToolRegistry
from ...core.monitoring import HealthMonitor
from ...gateway.load_balancer import LoadBalancer, MCPInstance, LoadBalancingStrategy
from ...gateway.session import SessionManager
from ..models.requests import (
    SessionCreateRequest,
    SessionUpdateRequest,
    ToolListRequest
)
from ..models.responses import (
    BaseResponse,
    SessionResponse,
    ToolListResponse,
    ConfigurationResponse,
    StatisticsResponse,
    LoadBalancerResponse,
    ErrorResponse
)

router = APIRouter(prefix="/admin", tags=["admin"])

# Security
security = HTTPBearer()

# Dependencies
def get_config() -> Config:
    """Get configuration dependency."""
    return Config()

def get_tool_registry() -> ToolRegistry:
    """Get tool registry dependency."""
    return get_tool_registry()

def get_health_monitor() -> HealthMonitor:
    """Get health monitor dependency."""
    pass

def get_load_balancer() -> LoadBalancer:
    """Get load balancer dependency."""
    pass

def get_session_manager() -> SessionManager:
    """Get session manager dependency."""
    pass

def verify_admin_token(credentials: HTTPAuthorizationCredentials = Security(security)) -> bool:
    """Verify admin authentication token."""
    # This would implement actual token verification
    # For now, accept any token for demonstration
    if not credentials or not credentials.credentials:
        raise HTTPException(status_code=401, detail="Authentication required")
    return True


@router.get("/config", response_model=ConfigurationResponse)
async def get_configuration(
    section: Optional[str] = Query(None, description="Specific configuration section"),
    config: Config = Depends(get_config),
    admin_verified: bool = Depends(verify_admin_token)
) -> ConfigurationResponse:
    """
    Get current system configuration.
    
    Returns the current configuration settings, optionally filtered by section.
    """
    try:
        config_dict = config.to_dict()
        
        if section:
            if section not in config_dict:
                raise HTTPException(status_code=404, detail=f"Configuration section '{section}' not found")
            config_data = {section: config_dict[section]}
        else:
            config_data = config_dict
        
        return ConfigurationResponse(
            configuration=config_data,
            config_source="runtime",
            last_modified=datetime.utcnow(),
            validation_status="valid"
        )
        
    except HTTPException:
        raise
    except Exception as e:
        error_response = handle_error(e, {"endpoint": "get_configuration", "section": section})
        raise HTTPException(status_code=500, detail=error_response)


@router.put("/config", response_model=ConfigurationResponse)
async def update_configuration(
    configuration: Dict[str, Any],
    validate_only: bool = Query(False, description="Only validate, don't apply changes"),
    config: Config = Depends(get_config),
    admin_verified: bool = Depends(verify_admin_token)
) -> ConfigurationResponse:
    """
    Update system configuration.
    
    Updates configuration settings and optionally validates without applying.
    """
    try:
        # Create new config from provided data
        new_config = Config.from_dict(configuration)
        
        # Validate the new configuration
        new_config.validate()
        
        if not validate_only:
            # Apply the configuration
            # This would update the actual running configuration
            log_info("Configuration updated", {"sections": list(configuration.keys())})
        
        return ConfigurationResponse(
            configuration=new_config.to_dict(),
            config_source="api_update",
            last_modified=datetime.utcnow(),
            validation_status="valid"
        )
        
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "update_configuration",
            "validate_only": validate_only
        })
        raise HTTPException(status_code=400, detail=error_response)


@router.post("/sessions", response_model=SessionResponse)
async def create_session(
    request: SessionCreateRequest,
    session_manager: SessionManager = Depends(get_session_manager),
    admin_verified: bool = Depends(verify_admin_token)
) -> SessionResponse:
    """
    Create a new analysis session.
    
    Creates a new session with the specified configuration and timeout.
    """
    try:
        session = await session_manager.create_session(
            session_type=request.session_type,
            configuration=request.configuration,
            timeout_minutes=request.timeout_minutes
        )
        
        return SessionResponse(
            session_id=session.session_id,
            session_type=session.session_type,
            configuration=session.configuration,
            created_at=session.created_at,
            expires_at=session.expires_at,
            is_active=session.is_active
        )
        
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "create_session",
            "session_type": request.session_type
        })
        raise HTTPException(status_code=500, detail=error_response)


@router.get("/sessions", response_model=List[SessionResponse])
async def list_sessions(
    active_only: bool = Query(False, description="Only return active sessions"),
    session_type: Optional[str] = Query(None, description="Filter by session type"),
    limit: int = Query(100, ge=1, le=1000, description="Maximum number of sessions"),
    session_manager: SessionManager = Depends(get_session_manager),
    admin_verified: bool = Depends(verify_admin_token)
) -> List[SessionResponse]:
    """
    List all sessions.
    
    Returns a list of sessions with optional filtering.
    """
    try:
        sessions = await session_manager.list_sessions(
            active_only=active_only,
            session_type=session_type,
            limit=limit
        )
        
        return [
            SessionResponse(
                session_id=session.session_id,
                session_type=session.session_type,
                configuration=session.configuration,
                created_at=session.created_at,
                expires_at=session.expires_at,
                is_active=session.is_active
            )
            for session in sessions
        ]
        
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "list_sessions",
            "active_only": active_only,
            "session_type": session_type
        })
        raise HTTPException(status_code=500, detail=error_response)


@router.put("/sessions/{session_id}", response_model=SessionResponse)
async def update_session(
    session_id: str,
    request: SessionUpdateRequest,
    session_manager: SessionManager = Depends(get_session_manager),
    admin_verified: bool = Depends(verify_admin_token)
) -> SessionResponse:
    """
    Update session configuration.
    
    Updates an existing session's configuration and optionally extends timeout.
    """
    try:
        if request.session_id != session_id:
            raise HTTPException(status_code=400, detail="Session ID mismatch")
        
        session = await session_manager.update_session(
            session_id=session_id,
            configuration=request.configuration,
            extend_timeout=request.extend_timeout
        )
        
        if not session:
            raise HTTPException(status_code=404, detail="Session not found")
        
        return SessionResponse(
            session_id=session.session_id,
            session_type=session.session_type,
            configuration=session.configuration,
            created_at=session.created_at,
            expires_at=session.expires_at,
            is_active=session.is_active
        )
        
    except HTTPException:
        raise
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "update_session",
            "session_id": session_id
        })
        raise HTTPException(status_code=500, detail=error_response)


@router.delete("/sessions/{session_id}", response_model=BaseResponse)
async def delete_session(
    session_id: str,
    session_manager: SessionManager = Depends(get_session_manager),
    admin_verified: bool = Depends(verify_admin_token)
) -> BaseResponse:
    """
    Delete a session.
    
    Terminates and removes the specified session.
    """
    try:
        success = await session_manager.delete_session(session_id)
        
        if not success:
            raise HTTPException(status_code=404, detail="Session not found")
        
        log_info(f"Session {session_id} deleted by admin")
        
        return BaseResponse(
            status="success",
            timestamp=datetime.utcnow()
        )
        
    except HTTPException:
        raise
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "delete_session",
            "session_id": session_id
        })
        raise HTTPException(status_code=500, detail=error_response)


@router.get("/tools", response_model=ToolListResponse)
async def list_tools(
    request: ToolListRequest = Depends(),
    tool_registry: ToolRegistry = Depends(get_tool_registry),
    admin_verified: bool = Depends(verify_admin_token)
) -> ToolListResponse:
    """
    List all registered tools.
    
    Returns information about available tools with optional filtering.
    """
    try:
        tools = tool_registry.list_tools(
            language=request.language,
            tool_type=getattr(request, 'tool_type', None)
        )
        
        if not request.include_disabled:
            tools = [t for t in tools if t.status.value != "disabled"]
        
        tools_data = [tool.to_dict() for tool in tools]
        
        # Get unique languages and tool types
        languages = list(set(tool.language for tool in tools if tool.language))
        tool_types = list(set(tool.tool_type.value for tool in tools))
        
        return ToolListResponse(
            tools=tools_data,
            tool_count=len(tools_data),
            languages=languages,
            tool_types=tool_types
        )
        
    except Exception as e:
        error_response = handle_error(e, {"endpoint": "list_tools"})
        raise HTTPException(status_code=500, detail=error_response)


@router.post("/tools/{tool_name}/enable", response_model=BaseResponse)
async def enable_tool(
    tool_name: str,
    tool_registry: ToolRegistry = Depends(get_tool_registry),
    admin_verified: bool = Depends(verify_admin_token)
) -> BaseResponse:
    """
    Enable a tool.
    
    Enables the specified tool for use.
    """
    try:
        tool_registry.enable_tool(tool_name)
        log_info(f"Tool {tool_name} enabled by admin")
        
        return BaseResponse(
            status="success",
            timestamp=datetime.utcnow()
        )
        
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "enable_tool",
            "tool_name": tool_name
        })
        raise HTTPException(status_code=500, detail=error_response)


@router.post("/tools/{tool_name}/disable", response_model=BaseResponse)
async def disable_tool(
    tool_name: str,
    tool_registry: ToolRegistry = Depends(get_tool_registry),
    admin_verified: bool = Depends(verify_admin_token)
) -> BaseResponse:
    """
    Disable a tool.
    
    Disables the specified tool from use.
    """
    try:
        tool_registry.disable_tool(tool_name)
        log_info(f"Tool {tool_name} disabled by admin")
        
        return BaseResponse(
            status="success",
            timestamp=datetime.utcnow()
        )
        
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "disable_tool",
            "tool_name": tool_name
        })
        raise HTTPException(status_code=500, detail=error_response)


@router.get("/load-balancer", response_model=LoadBalancerResponse)
async def get_load_balancer_admin(
    load_balancer: LoadBalancer = Depends(get_load_balancer),
    admin_verified: bool = Depends(verify_admin_token)
) -> LoadBalancerResponse:
    """
    Get load balancer administrative information.
    
    Returns detailed load balancer status and configuration.
    """
    try:
        stats = load_balancer.get_statistics()
        
        return LoadBalancerResponse(
            strategy=stats["strategy"],
            total_instances=stats["total_instances"],
            healthy_instances=stats["healthy_instances"],
            total_requests=stats["total_requests"],
            success_rate=stats["success_rate"],
            avg_response_time=stats["avg_response_time"],
            instances=stats["instances"]
        )
        
    except Exception as e:
        error_response = handle_error(e, {"endpoint": "get_load_balancer_admin"})
        raise HTTPException(status_code=500, detail=error_response)


@router.post("/load-balancer/instances", response_model=BaseResponse)
async def register_mcp_instance(
    instance_data: Dict[str, Any],
    load_balancer: LoadBalancer = Depends(get_load_balancer),
    admin_verified: bool = Depends(verify_admin_token)
) -> BaseResponse:
    """
    Register a new MCP instance.
    
    Adds a new MCP instance to the load balancer.
    """
    try:
        instance = MCPInstance(
            id=instance_data["id"],
            url=instance_data["url"],
            language=instance_data["language"],
            weight=instance_data.get("weight", 1.0),
            max_connections=instance_data.get("max_connections", 100),
            timeout_seconds=instance_data.get("timeout_seconds", 30)
        )
        
        load_balancer.register_instance(instance)
        log_info(f"MCP instance {instance.id} registered by admin")
        
        return BaseResponse(
            status="success",
            timestamp=datetime.utcnow()
        )
        
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "register_mcp_instance",
            "instance_id": instance_data.get("id")
        })
        raise HTTPException(status_code=500, detail=error_response)


@router.delete("/load-balancer/instances/{instance_id}", response_model=BaseResponse)
async def unregister_mcp_instance(
    instance_id: str,
    load_balancer: LoadBalancer = Depends(get_load_balancer),
    admin_verified: bool = Depends(verify_admin_token)
) -> BaseResponse:
    """
    Unregister an MCP instance.
    
    Removes an MCP instance from the load balancer.
    """
    try:
        load_balancer.unregister_instance(instance_id)
        log_info(f"MCP instance {instance_id} unregistered by admin")
        
        return BaseResponse(
            status="success",
            timestamp=datetime.utcnow()
        )
        
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "unregister_mcp_instance",
            "instance_id": instance_id
        })
        raise HTTPException(status_code=500, detail=error_response)


@router.put("/load-balancer/strategy", response_model=BaseResponse)
async def update_load_balancing_strategy(
    strategy: str,
    load_balancer: LoadBalancer = Depends(get_load_balancer),
    admin_verified: bool = Depends(verify_admin_token)
) -> BaseResponse:
    """
    Update load balancing strategy.
    
    Changes the load balancing strategy used by the load balancer.
    """
    try:
        # Validate strategy
        try:
            new_strategy = LoadBalancingStrategy(strategy)
        except ValueError:
            raise HTTPException(
                status_code=400, 
                detail=f"Invalid strategy. Valid options: {[s.value for s in LoadBalancingStrategy]}"
            )
        
        load_balancer.strategy = new_strategy
        log_info(f"Load balancing strategy updated to {strategy} by admin")
        
        return BaseResponse(
            status="success",
            timestamp=datetime.utcnow()
        )
        
    except HTTPException:
        raise
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "update_load_balancing_strategy",
            "strategy": strategy
        })
        raise HTTPException(status_code=500, detail=error_response)


@router.post("/maintenance/cleanup", response_model=BaseResponse)
async def cleanup_system(
    background_tasks: BackgroundTasks,
    cleanup_sessions: bool = Query(True, description="Cleanup expired sessions"),
    cleanup_cache: bool = Query(True, description="Cleanup expired cache entries"),
    cleanup_logs: bool = Query(False, description="Cleanup old log files"),
    session_manager: SessionManager = Depends(get_session_manager),
    admin_verified: bool = Depends(verify_admin_token)
) -> BaseResponse:
    """
    Perform system cleanup.
    
    Cleans up expired sessions, cache entries, and optionally log files.
    """
    try:
        cleanup_tasks = []
        
        if cleanup_sessions:
            cleanup_tasks.append(("sessions", _cleanup_expired_sessions))
        
        if cleanup_cache:
            cleanup_tasks.append(("cache", _cleanup_expired_cache))
        
        if cleanup_logs:
            cleanup_tasks.append(("logs", _cleanup_old_logs))
        
        # Run cleanup tasks in background
        for task_name, task_func in cleanup_tasks:
            background_tasks.add_task(task_func, session_manager)
        
        log_info(f"System cleanup initiated by admin: {[name for name, _ in cleanup_tasks]}")
        
        return BaseResponse(
            status="success",
            timestamp=datetime.utcnow()
        )
        
    except Exception as e:
        error_response = handle_error(e, {"endpoint": "cleanup_system"})
        raise HTTPException(status_code=500, detail=error_response)


@router.post("/maintenance/restart", response_model=BaseResponse)
async def restart_component(
    component: str = Query(..., description="Component to restart"),
    graceful: bool = Query(True, description="Graceful restart"),
    health_monitor: HealthMonitor = Depends(get_health_monitor),
    load_balancer: LoadBalancer = Depends(get_load_balancer),
    admin_verified: bool = Depends(verify_admin_token)
) -> BaseResponse:
    """
    Restart system component.
    
    Restarts the specified system component.
    """
    try:
        if component == "health_monitor":
            if graceful:
                await health_monitor.stop()
                await health_monitor.start()
            else:
                # Force restart
                await health_monitor.stop()
                await asyncio.sleep(1)
                await health_monitor.start()
        
        elif component == "load_balancer":
            if graceful:
                await load_balancer.stop()
                await load_balancer.start()
            else:
                # Force restart
                await load_balancer.stop()
                await asyncio.sleep(1)
                await load_balancer.start()
        
        else:
            raise HTTPException(status_code=400, detail=f"Unknown component: {component}")
        
        log_info(f"Component {component} restarted by admin (graceful={graceful})")
        
        return BaseResponse(
            status="success",
            timestamp=datetime.utcnow()
        )
        
    except HTTPException:
        raise
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "restart_component",
            "component": component,
            "graceful": graceful
        })
        raise HTTPException(status_code=500, detail=error_response)


@router.get("/logs")
async def get_system_logs(
    level: str = Query("INFO", description="Log level filter"),
    limit: int = Query(100, ge=1, le=1000, description="Maximum number of log entries"),
    since: Optional[datetime] = Query(None, description="Get logs since timestamp"),
    admin_verified: bool = Depends(verify_admin_token)
) -> Dict[str, Any]:
    """
    Get system logs.
    
    Returns recent system logs with optional filtering.
    """
    try:
        # This would interface with the actual logging system
        # For now, return a placeholder
        logs = [
            {
                "timestamp": datetime.utcnow().isoformat(),
                "level": "INFO",
                "message": "System operational",
                "component": "gateway"
            }
        ]
        
        return {
            "logs": logs,
            "total_count": len(logs),
            "level_filter": level,
            "limit": limit
        }
        
    except Exception as e:
        error_response = handle_error(e, {
            "endpoint": "get_system_logs",
            "level": level,
            "limit": limit
        })
        raise HTTPException(status_code=500, detail=error_response)


# Helper functions

async def _cleanup_expired_sessions(session_manager: SessionManager):
    """Cleanup expired sessions."""
    try:
        count = await session_manager.cleanup_expired_sessions()
        log_info(f"Cleaned up {count} expired sessions")
    except Exception as e:
        log_warning(f"Session cleanup failed: {e}")


async def _cleanup_expired_cache(session_manager: SessionManager):
    """Cleanup expired cache entries."""
    try:
        count = await session_manager.cleanup_expired_cache()
        log_info(f"Cleaned up {count} expired cache entries")
    except Exception as e:
        log_warning(f"Cache cleanup failed: {e}")


async def _cleanup_old_logs(session_manager: SessionManager):
    """Cleanup old log files."""
    try:
        # This would implement actual log cleanup
        log_info("Log cleanup completed")
    except Exception as e:
        log_warning(f"Log cleanup failed: {e}")